/* Copyright 2009, Sam Pullara Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License */ package com.sampullara.findmyiphone; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.CookieStore; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.cookie.Cookie; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonParser; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class FindMyDevice extends HttpServlet { @Override protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { String username = httpServletRequest.getParameter("username"); String password = httpServletRequest.getParameter("password"); if (username == null || password == null) { httpServletResponse.sendError(400, "You must specify a MobileMe username and password"); return; } httpServletResponse.setContentType("application/json"); writeDeviceLocations(httpServletResponse.getWriter(), username, password); } private static void writeDeviceLocations(Writer out, String username, String password) throws IOException { // Initialize the HTTP client DefaultHttpClient hc = new DefaultHttpClient(); // Authorize with Apple's mobile me service HttpGet auth = new HttpGet("https://auth.apple.com/authenticate?service=DockStatus&realm=primary-me&formID=loginForm&username=" + username + "&password=" + password + "&returnURL=aHR0cHM6Ly9zZWN1cmUubWUuY29tL3dvL1dlYk9iamVjdHMvRG9ja1N0YXR1cy53b2Evd2EvdHJhbXBvbGluZT9kZXN0aW5hdGlvblVybD0vYWNjb3VudA%3D%3D"); hc.execute(auth); auth.abort(); // Pull the isc-secure.me.com cookie out so we can set the X-Mobileme-Isc header properly String isc = extractIscCode(hc); // Get access to the devices and find out their ids HttpPost devicemgmt = new HttpPost("https://secure.me.com/wo/WebObjects/DeviceMgmt.woa/?lang=en"); devicemgmt.addHeader("X-Mobileme-Version", "1.0"); devicemgmt.addHeader("X-Mobileme-Isc", isc); devicemgmt.setEntity(new UrlEncodedFormEntity(new ArrayList<NameValuePair>())); HttpResponse devicePage = hc.execute(devicemgmt); // Extract the device ids from their html encoded in json ByteArrayOutputStream os = new ByteArrayOutputStream(); devicePage.getEntity().writeTo(os); os.close(); Matcher m = Pattern.compile("DeviceMgmt.deviceIdMap\\['[0-9]+'\\] = '([a-z0-9]+)';").matcher(new String(os.toByteArray())); List<String> deviceList = new ArrayList<String>(); while (m.find()) { deviceList.add(m.group(1)); } // For each available device, get the location JsonFactory jf = new JsonFactory(); JsonGenerator jg = jf.createJsonGenerator(out); jg.writeStartObject(); for (String device : deviceList) { HttpPost locate = new HttpPost("https://secure.me.com/wo/WebObjects/DeviceMgmt.woa/wa/LocateAction/locateStatus"); locate.addHeader("X-Mobileme-Version", "1.0"); locate.addHeader("X-Mobileme-Isc", isc); locate.setEntity(new StringEntity("postBody={\"deviceId\": \"" + device + "\", \"deviceOsVersion\": \"7A341\"}")); locate.setHeader("Content-type", "application/json"); HttpResponse location = hc.execute(locate); InputStream inputStream = location.getEntity().getContent(); JsonParser jp = jf.createJsonParser(inputStream); jp.nextToken(); // ugly jg.writeFieldName(device); jg.copyCurrentStructure(jp); inputStream.close(); } jg.close(); out.close(); } private static String extractIscCode(DefaultHttpClient hc) { CookieStore cookies = hc.getCookieStore(); for (Cookie cookie : cookies.getCookies()) { if (cookie.getName().equals("isc-secure.me.com")) { return cookie.getValue(); } } return null; } }